#ifndef VISITOR_H_
#define VISITOR_H_

#include <PLCSTParserBaseVisitor.h>
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Verifier.h"

#include "plc2llvm/ScopeSystem/Scope.h"

class Visitor : public plcst::PLCSTParserBaseVisitor {
private:
    plcst::PLCSTParser* parser;
    // 解析的token流，用于报错使用
    antlr4::TokenStream* tokens;
    std::string outputPath;
    void creatAllBasicType();
    
public:
    const antlr4::TokenStream* getTokenStream();

    llvm::LLVMContext context;
    llvm::Module* module;
    llvm::IRBuilder<>* builder;

public:
    Visitor(plcst::PLCSTParser* parser, llvm::StringRef moduleName, std::string outputPath = ".");

    ~Visitor() override;

    std::any visitStartpoint(plcst::PLCSTParser::StartpointContext* ctx) override;

    std::any visitProg_Decl(plcst::PLCSTParser::Prog_DeclContext *ctx) override;

    std::any visitFunc_Decl(plcst::PLCSTParser::Func_DeclContext *ctx) override;

    std::any visitProg_Type_Name(plcst::PLCSTParser::Prog_Type_NameContext *ctx) override;

    std::any visitVar_Decls(plcst::PLCSTParser::Var_DeclsContext *ctx) override;

    std::any visitVar_Decl_Init(plcst::PLCSTParser::Var_Decl_InitContext *ctx) override;

    std::any visitVariable_List(plcst::PLCSTParser::Variable_ListContext *ctx) override;

    std::any visitVariable_Name(plcst::PLCSTParser::Variable_NameContext *ctx) override;

    std::any visitSimple_Spec_Init(plcst::PLCSTParser::Simple_Spec_InitContext *ctx) override;

    std::any visitCommon_Var_Decl_Init(plcst::PLCSTParser::Common_Var_Decl_InitContext *ctx) override;

    std::any visitSimple_Spec(plcst::PLCSTParser::Simple_SpecContext *ctx) override;

    std::any visitElem_Type_Name(plcst::PLCSTParser::Elem_Type_NameContext *ctx) override;

    std::any visitNumeric_Type_Name(plcst::PLCSTParser::Numeric_Type_NameContext *ctx) override;

    std::any visitFunc_Var_Decls(plcst::PLCSTParser::Func_Var_DeclsContext *ctx) override;

    std::any visitStmt_List(plcst::PLCSTParser::Stmt_ListContext *ctx) override;

    std::any visitStmt(plcst::PLCSTParser::StmtContext *ctx) override;

    std::any visitIteration_Stmt(plcst::PLCSTParser::Iteration_StmtContext *ctx) override;

    std::any visitFor_Stmt(plcst::PLCSTParser::For_StmtContext *ctx) override;


    std::any visitControl_Variable(plcst::PLCSTParser::Control_VariableContext *ctx) override;

    std::any visitFor_List(plcst::PLCSTParser::For_ListContext *ctx) override;

    std::any visitExpression(plcst::PLCSTParser::ExpressionContext *ctx) override;

    // ************expression part************
    std::any visitConstant_Expr(plcst::PLCSTParser::Constant_ExprContext* ctx) override;

    std::any visitXor_Expr(plcst::PLCSTParser::Xor_ExprContext *ctx) override;

    std::any visitAnd_Expr(plcst::PLCSTParser::And_ExprContext *ctx) override;

    std::any visitCompare_Expr(plcst::PLCSTParser::Compare_ExprContext *ctx) override;

    std::any visitEqu_Expr(plcst::PLCSTParser::Equ_ExprContext *ctx) override;

    std::any visitAdd_Expr(plcst::PLCSTParser::Add_ExprContext *ctx) override;

    std::any visitTerm(plcst::PLCSTParser::TermContext *ctx) override;

    std::any visitPower_Expr(plcst::PLCSTParser::Power_ExprContext *ctx) override;

    std::any visitUnary_Expr(plcst::PLCSTParser::Unary_ExprContext *ctx) override;

    std::any visitPrimary_Expr(plcst::PLCSTParser::Primary_ExprContext *ctx) override;

    std::any visitBit_Str_Literal(plcst::PLCSTParser::Bit_Str_LiteralContext *ctx) override;
    
    std::any visitIdentifier(plcst::PLCSTParser::IdentifierContext* ctx) override;

    std::any visitParen_Surrounded_Expr(plcst::PLCSTParser::Paren_Surrounded_ExprContext *ctx) override;

    std::any visitInt_Literal(plcst::PLCSTParser::Int_LiteralContext *ctx) override;

    std::any visitReal_Literal(plcst::PLCSTParser::Real_LiteralContext *ctx) override;

    std::any visitEnum_Value(plcst::PLCSTParser::Enum_ValueContext *ctx) override;

    std::any visitVariable_Access(plcst::PLCSTParser::Variable_AccessContext *ctx) override;

    std::any visitFunc_Call(plcst::PLCSTParser::Func_CallContext *ctx) override;

    std::any visitRef_Value(plcst::PLCSTParser::Ref_ValueContext *ctx) override;

    std::any visitConstant(plcst::PLCSTParser::ConstantContext *ctx) override;
    // ************end of expression************


    std::any visitAssign_Stmt(plcst::PLCSTParser::Assign_StmtContext *ctx) override;

    std::any visitVar_Assign(plcst::PLCSTParser::Var_AssignContext *ctx) override;

    std::any visitVariable(plcst::PLCSTParser::VariableContext *ctx) override;

    std::any visitSymbolic_Variable(plcst::PLCSTParser::Symbolic_VariableContext *ctx) override;

    std::any visitVar_Access(plcst::PLCSTParser::Var_AccessContext *ctx) override;

    std::any visitRef_Deref(plcst::PLCSTParser::Ref_DerefContext *ctx) override;

    std::any visitMulti_Elem_Var(plcst::PLCSTParser::Multi_Elem_VarContext *ctx) override;
};


#endif